package com.jvyou.mybatis.builder.mapper;

import com.jvyou.mybatis.annotations.*;
import com.jvyou.mybatis.cache.Cache;
import com.jvyou.mybatis.mapping.MappedStatement;
import com.jvyou.mybatis.mapping.SqlCommandType;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author 橘柚
 * @version 1.0-SNAPSHOT
 * @Date 2024/7/24 18:46
 * @Description Mapper 解析器
 */
public class MethodMapperParser {

    public MappedStatement parseMethod(final Class<?> aClass, final Method method, final Cache cache) {
        // 获取 SqlCommandType
        SqlCommandType sqlCommandType = getSqlCommandType(method);
        if (sqlCommandType == null) {
            return null; // Skip methods without SQL annotations
        }
        // 获取原始的 SQL（未解析的SQL）
        String originalSql = getOriginalSql(method, sqlCommandType);
        // 获取返回值类型
        Class<?> returnType = getReturnType(method);
        boolean isSelectMany = isSelectMany(method);

        return MappedStatement.builder()
                .id(aClass.getName() + "." + method.getName())
                .sql(originalSql)
                .resultType(returnType)
                .sqlCommandType(sqlCommandType)
                .selectMany(isSelectMany)
                .cache(cache)
                .build();
    }


    /**
     * 获取 SqlCommandType
     *
     * @param method Mapper 方法
     * @return SqlCommandType
     */
    private SqlCommandType getSqlCommandType(Method method) {
        if (method.isAnnotationPresent(Select.class)) {
            return SqlCommandType.SELECT;
        } else if (method.isAnnotationPresent(Update.class)) {
            return SqlCommandType.UPDATE;
        } else if (method.isAnnotationPresent(Insert.class)) {
            return SqlCommandType.INSERT;
        } else if (method.isAnnotationPresent(Delete.class)) {
            return SqlCommandType.DELETE;
        } else if (method.isAnnotationPresent(XmlMapper.class)) {
            return SqlCommandType.UNKNOWN;
        }
        return null;
    }

    private String getOriginalSql(Method method, SqlCommandType sqlCommandType) {
        switch (sqlCommandType) {
            case SELECT:
                return method.getAnnotation(Select.class).value();
            case UPDATE:
                return method.getAnnotation(Update.class).value();
            case INSERT:
                return method.getAnnotation(Insert.class).value();
            case DELETE:
                return method.getAnnotation(Delete.class).value();
            case UNKNOWN:
                return "";
            default:
                throw new IllegalArgumentException("Unsupported SqlCommandType: " + sqlCommandType);
        }
    }

    private Class<?> getReturnType(Method method) {
        Type genericReturnType = method.getGenericReturnType();
        // 如果返回类型是一个普通的类
        if (genericReturnType instanceof Class) {
            return (Class<?>) genericReturnType;
        } else if (genericReturnType instanceof ParameterizedType) {
            // 如果返回类型是一个带有泛型参数的类型
            return ((ParameterizedType) genericReturnType).getActualTypeArguments().length > 0
                    ? (Class<?>) ((ParameterizedType) genericReturnType).getActualTypeArguments()[0]
                    : (Class<?>) ((ParameterizedType) genericReturnType).getRawType();
        }
        throw new IllegalArgumentException("Unsupported return type: " + genericReturnType);
    }

    private boolean isSelectMany(Method method) {
        Type genericReturnType = method.getGenericReturnType();
        return genericReturnType instanceof ParameterizedType;
    }

}
